package com.om39a.plm.parser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.om39a.plm.crawler.DefaultBrowser;
import com.om39a.plm.crawler.PLMBrowser;
import com.om39a.plm.exceptions.NoNextPageException;
import com.om39a.plm.exceptions.PageLoadFailedException;
import com.om39a.plm.utils.PLMFileUtils;

/**
 * @author om39a
 * 
 */
public class ParserUserProfilePage extends PLMParser {

	static Logger logger = Logger.getLogger(ParserUserProfilePage.class);

	static PLMFileUtils plmFileUtils = createFileReaderInstance();

	private static PLMFileUtils createFileReaderInstance() {
		if (plmFileUtils == null) {
			try {
				return new PLMFileUtils("UserDataAvailable.txt");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return plmFileUtils;
	}

	List<String> userDetailsAvailable = readListOfUsersAvailable();

	private List<String> readListOfUsersAvailable() {
		if (userDetailsAvailable == null) {
			try {
				return plmFileUtils.readFileToList();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return userDetailsAvailable;
	}

	public static final String PATIENT = "Patient";
	public static final String DEACTIVATED = "Deactivated";
	public static final String PLM_ALUM = "PLM Alum";
	public static final String ALUMNI = "Alumni";
	public static final String PLM_RESEARCHER = "Plm-researcher";
	public static final String ADMIN = "Admin";
	public static final String MODERATOR = "Moderator";

	/**
	 * @param fileContent
	 * @return
	 */
	public PLMUser parse(String fileContent) {
		logger.info("Entring into parse - fileContent");
		ArrayList<PLMUserCondition> conditions = new ArrayList<PLMUserCondition>();
		PLMUser plmUser = new PLMUser();
		try {
			Document doc = Jsoup.parse(fileContent);
			getProfileSummary(doc, plmUser);

			// If user is already present, don't scrape its url

			if (!userDetailsAvailable.contains(plmUser.getUserName())) {
				Elements nuggetBlock = doc
						.getElementsByAttributeValueContaining("class",
								"nugget-block");
				getUserType(plmUser, nuggetBlock);
				getDataQualityStars(plmUser, nuggetBlock);
				Elements profileBio = doc.select("div[class=profile_bio]");
				Elements profileActivity = profileBio
						.select("div[class=profile_activity]");
				Element countElements = profileActivity.select("dl").last();
				getPostCount(plmUser, countElements);
				getHelpfullMarksCount(plmUser, countElements);
				getMemberSince(plmUser, profileBio);
				getPrimaryCondition(doc, conditions, plmUser);
				getSecondaryConditions(doc, conditions, plmUser);
				getFollowerFollowingUsers(plmUser, doc);
				plmUser.setConditions(conditions);
				return plmUser;
			} else {
				return null;
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.info(e);
		}
		logger.info("Exiting from parse");
		return plmUser;
	}

	private void getFollowerFollowingUsers(PLMUser plmUser, Document doc) {

		Elements listElements = doc.select("dl[class=expando-menu]").first()
				.select("dd").first().select("li");
		for (Element element : listElements) {
			if (element.text().contains("Followers")) {
				plmUser.setFollowersProfileUrl(element.select("a[href]").attr(
						"href"));
			} else if (element.text().contains("Following")) {
				plmUser.setFollowingProfileUrl(element.select("a[href]").attr(
						"href"));
			}
		}

		PLMBrowser browser = new DefaultBrowser();
		// ---
		ParserFollowersPage parseFollowersPage = new ParserFollowersPage();
		ArrayList<String> followers = new ArrayList<String>();
		String followersUrl = plmUser.getFollowersProfileUrl();
		String followersPageContent = null;

		if (StringUtils.isNotEmpty(followersUrl)) {
			try {
				followersPageContent = browser.execute(followersUrl);
			} catch (PageLoadFailedException e1) {
				e1.printStackTrace();
			}

			while (true) {
				String nextPageUrl;
				try {
					parseFollowersPage.parse(followersPageContent, followers);
					nextPageUrl = parseFollowersPage
							.nextPage(followersPageContent);
					if (null == nextPageUrl || "".equals(nextPageUrl)) {
						break;
					}
				} catch (NoNextPageException e) {
					break;
				}

				try {
					followersPageContent = browser.execute(nextPageUrl);
				} catch (PageLoadFailedException e) {
					e.printStackTrace();
				}
			}
		}

		// --
		ParserFollowingPage parseFollowingPage = new ParserFollowingPage();
		ArrayList<String> followingUsers = new ArrayList<String>();

		if (StringUtils.isNotBlank(plmUser.getFollowingProfileUrl())) {

			String followingUrl = plmUser.getFollowingProfileUrl() + "/people";
			String followingUsersPageContent = null;
			try {
				followingUsersPageContent = browser.execute(followingUrl);
			} catch (PageLoadFailedException e1) {
				e1.printStackTrace();
			}

			while (true) {
				String nextPageUrl;
				try {
					parseFollowingPage.parse(followingUsersPageContent,
							followingUsers);
					nextPageUrl = parseFollowersPage
							.nextPage(followingUsersPageContent);
					if (null == nextPageUrl || "".equals(nextPageUrl)) {
						break;
					}
				} catch (NoNextPageException e) {
					break;
				}
				try {
					followingUsersPageContent = browser.execute(nextPageUrl);
				} catch (PageLoadFailedException e) {
					e.printStackTrace();
				}
			}
		}
		plmUser.setFollowers(followers);
		plmUser.setFollowing(followingUsers);
	}

	private static void getSecondaryConditions(Document doc,
			List<PLMUserCondition> conditions, PLMUser profileBio) {
		Elements otherConditions = doc.select("div[class=profile_conditions]")
				.select("li");
		for (Element otherCondition : otherConditions) {
			PLMUserCondition condition = new PLMUserCondition();
			condition.setUserID(profileBio.getUserId());
			condition.setUserName(profileBio.getUserName());
			condition.setConditionName(otherCondition.select(
					"span[class=condition-name]").text());
			Element ciElement = otherCondition.select("dl[class=ci]").first();
			Elements dts = ciElement.select("dt");
			Elements dds = ciElement.select("dd");
			for (int i = 0; i < dts.size(); i++) {
				populateConditionDate(dds, condition, i, dts.get(i).text());
			}
			conditions.add(condition);
		}
	}

	private static void populateConditionDate(Elements dds,
			PLMUserCondition condition, int i, String title) {
		if (title.equalsIgnoreCase("First symptom")) {
			condition.setFirstSymptomDate(dds.get(i).text());
		} else if (title.equalsIgnoreCase("Diagnosis")) {
			condition.setDiagnosiDate(dds.get(i).text());
		} else if (title.equalsIgnoreCase("Stopped")) {
			condition.setStopedDate(dds.get(i).text());
		} else if (title.equalsIgnoreCase("Stopped Reason")) {
			condition.setStopedReason(dds.get(i).text());
		} else if (title.equalsIgnoreCase("Occurred")) {
			condition.setOccured(dds.get(i).text());
		}
	}

	private static void getPrimaryCondition(Document doc,
			List<PLMUserCondition> conditions, PLMUser profileBio) {
		Elements primaryConditionElements = doc
				.select("div[class=profile_primary]");

		Elements diagoniseDetails = doc.select("div[class=ci diagnosis]");

		PLMUserCondition condition = new PLMUserCondition();

		condition.setUserID(profileBio.getUserId());
		condition.setUserName(profileBio.getUserName());
		condition.setConditionName(primaryConditionElements
				.select("dl[class=ci primary]").select("dd").text()
				.replaceAll("and.*", ""));
		condition.setPrimaryCondition(true);
		String diagoniseDetail = diagoniseDetails.toString();
		condition.setFirstSymptomDate(diagoniseDetail.replaceAll(
				"First symptom", "").replaceAll("Diagnosis.*", ""));
		condition
				.setDiagnosiDate(diagoniseDetail.replaceAll(".*Diagnosis", ""));

		conditions.add(condition);
	}

	private static void getMemberSince(PLMUser plmUser, Elements profileBio) {
		Elements dateElements = profileBio.select("div[class=profile_status]");
		plmUser.setDateJoined(dateElements.text()
				.replaceAll("Member since:", "").replaceAll("Last Login.*", ""));
	}

	private static void getHelpfullMarksCount(PLMUser plmUser, Element elements) {
		plmUser.setNoOfHelpfulMarks(elements.select("dd").last().text()
				.replaceAll("\\D", ""));
	}

	private static void getPostCount(PLMUser plmUser, Element elements) {
		plmUser.setNoOfPosts(elements.select("dd").first().text()
				.replaceAll("\\D", ""));
	}

	private static void getDataQualityStars(PLMUser plmUser,
			Elements nuggetBlock) {
		Elements iconSets = nuggetBlock.select("dl[class^=icon-set ]");
		if ("".equals(iconSets.select("dd[class^=quality ]").text())) {
			plmUser.setDataQualityStars("NA");
		} else {
			plmUser.setDataQualityStars(iconSets.select("dd[class^=quality ]")
					.text().replace("Data Quality:", "").trim());
		}
	}

	private static void getUserType(PLMUser plmUser, Elements nuggetBlock) {
		if (nuggetBlock.text().contains(MODERATOR)) {
			plmUser.setUserType(MODERATOR);
		} else if (nuggetBlock.text().contains(ADMIN)) {
			plmUser.setUserType(ADMIN);
		} else if (nuggetBlock.text().contains(PLM_RESEARCHER)) {
			plmUser.setUserType(PLM_RESEARCHER);
		} else if (nuggetBlock.text().contains(ALUMNI)) {
			plmUser.setUserType(ALUMNI);
		} else if (nuggetBlock.text().contains(PLM_ALUM)) {
			plmUser.setUserType(PLM_ALUM);
		} else if (nuggetBlock.text().contains(DEACTIVATED)) {
			plmUser.setUserType(DEACTIVATED);
		} else {
			plmUser.setUserType(PATIENT);
		}
	}

	/**
	 * Get user name, gender, age, place
	 * 
	 * @param doc
	 * @param plmUser
	 */
	private static void getProfileSummary(Document doc, PLMUser plmUser) {
		// Get user name, gender, age, place
		Element element = doc.select("dl[class=profile_summary]").first();
		plmUser.setUserId(element.select("a[href]").text());
		plmUser.setUserName(element.select("a[href]").text());
		try {
			String[] sexAndAge = element.select("dd").get(0).text().split(",");
			plmUser.setGender(sexAndAge[0]);
			plmUser.setAge(sexAndAge[1]);
		} catch (Exception e) {
			e.printStackTrace();
		}
		plmUser.setPlace(element.select("dd").get(1).text());
	}

}
